/* eslint-disable @typescript-eslint/no-explicit-any */
import ENV from "@/utils/env"
import { CustomError, ErrorCode, ErrorFactory } from "@/utils/error"
import { createLogger } from "@/utils/logger"
import { AxiosError, AxiosResponse } from "axios"
import qs from "qs"
import {
    PostmanApi as PostmanApiV1,
    HttpClient as PostmanHttpClientV1,
} from "./postman_api_filbet_client_v1"

//crob
import { tokenStore } from "@/utils/cached"
import { CBOR, genStorageKey } from "@/utils/common"
import { getDefaultStore } from "jotai"

const logger = createLogger("Api 攔截器")
const cborLogger = createLogger("CBOR") // 專門用於CBOR日誌
const store = getDefaultStore()

export function getDeviceCode(): 24 | 25 {
    const userAgent = navigator.userAgent
    // 24 = pc , 25 = mobile
    if (userAgent.includes("Macintosh")) {
        return 24
    }
    return 25
}

const cbor_required_url_regex_list = [
    /^\/game\/(.*)/g,
    /^\/finance\/(.*)/g,
    /^\/member\/(.*)/g,
    /^\/ocr\/(.*)/g,
    /^\/api\/v2\/(.*)/g,
]

const Apis = {
    get v1() {
        const _client = new PostmanHttpClientV1({
            baseURL: "/",
            paramsSerializer(params) {
                return qs.stringify(params, {
                    arrayFormat: "repeat", // 使用重複的 key 代替 'key[]'
                })
            },
        })

        _client.instance.interceptors.request.use((config) => {
            // get token
            const token = tokenStore.get().accessToken
            config.baseURL = ENV.base_url_api_v1
            if (token) {
                config.headers.Authorization = `Bearer ${token}`
            }

            // /api/v2 使用 cbor 格式，其他使用 json 格式
            if (
                config.url &&
                cbor_required_url_regex_list.some((regex) =>
                    new RegExp(regex).test(config.url ?? ""),
                )
            ) {
                config.baseURL = "/"
                config.headers.d = "25"
                config.headers.lang = "en_US"
                config.responseType = "arraybuffer"
                if (token) {
                    config.headers.t = token
                    config.headers.Authorization = `Bearer ${token}`
                } else {
                    config.headers.t = ""
                    config.headers.Authorization = ""
                }

                // 合併所有請求日誌為一條
                const requestInfo: {
                    url: string
                    rawData: any
                    encodedData: any
                } = {
                    url: `${config.method} ${config.url}`,
                    rawData: config.data,
                    encodedData: null,
                }

                if (config.method?.toLocaleLowerCase() !== "get" && config.data) {
                    // 編碼數據並保存到日誌對象
                    if (config.headers["Content-Type"] === "multipart/form-data") {
                        logger.info("multipart/form-data", config.data)
                        return config
                    } else {
                        requestInfo.encodedData = CBOR.encode(config.data)
                        config.data = requestInfo.encodedData
                    }
                }

                cborLogger.info(`CBOR請求`, requestInfo)
            }
            logger.debug("PostmanHttpClientV1 Request", config)
            return config
        })
        // @ts-ignore
        _client.instance.interceptors.response.use(async (_response) => {
            logger.debug("PostmanHttpClientV1 Response", _response)
            try {
                const response = _response as AxiosResponse<globalThis.ApiTypes.AxiosResponseData>

                /**
                 * /api/v2 使用 cbor 格式做解析
                 */
                if (
                    response.config.url &&
                    cbor_required_url_regex_list.some((regex) =>
                        new RegExp(regex).test(response.config.url ?? ""),
                    ) &&
                    response.config.responseType === "arraybuffer"
                ) {
                    const response = _response as AxiosResponse<ArrayBuffer>
                    return cborResponseHandler(response)
                }
                /**
                 * 其他使用 json 格式做解析
                 */
                const data = response.data
                if (data.success) {
                    return response
                }
                throw ErrorFactory.createServerError("Unknown error")
            } catch (_error) {
                if (_error instanceof CustomError) {
                    const error = _error as CustomError
                    throw error
                }
                const error = _error as AxiosError

                switch (error.status) {
                    case 401:
                        tokenStore.clear()
                        localStorage.removeItem(genStorageKey("token"))
                        throw ErrorFactory.create(
                            ErrorCode.AUTHENTICATION_ERROR,
                            ErrorCode.AUTHENTICATION_ERROR,
                            error,
                        )
                }
                throw ErrorFactory.create(ErrorCode.SERVER_ERROR, ErrorCode.SERVER_ERROR)
            }
        })
        const _api = new PostmanApiV1(_client)
        return {
            ..._api.game,
            ..._api.api,
            ..._api.member,
            ..._api.finance,
        }
    },
    get v2() {
        const _client = new PostmanHttpClientV1({
            baseURL: ENV.dev_mode ? "/" : ENV.base_url_api_v1,
            headers: {
                d: "24",
                lang: "en_US",
                accept: "application/cbor",
            },
            paramsSerializer(params) {
                return qs.stringify(params, {
                    arrayFormat: "repeat", // 使用重複的 key 代替 'key[]'
                })
            },
        })
        _client.instance.interceptors.request.use((config) => {
            logger.debug("PostmanHttpClientV1 Request", config)
            // get token
            const token = tokenStore.get().accessToken
            if (token) {
                config.headers.Authorization = `Bearer ${token}`
                config.headers.t = token
            }
            return config
        })
        const _api = {
            async getGameUrlWithLaunchToken(code: string) {
                const response = await _client.request({
                    method: "GET",
                    path: "/api/v2/game/launch",
                    query: { code },
                    format: "arraybuffer",
                })

                const decoded = CBOR.decode<{
                    status: boolean
                    data: string
                }>(response.data)

                // 合併所有響應日誌為一條
                cborLogger.info(`CBOR響應 [/api/v2/game/launch]:`, {
                    rawData: response.data,
                    decodedData: decoded,
                })

                if (!decoded.status) {
                    throw ErrorFactory.create(
                        ErrorCode.SERVER_ERROR,
                        ErrorCode.SERVER_ERROR,
                        decoded,
                    )
                }
                return decoded.data
            },
        }
        return _api
    },
}

export default Apis

function cborResponseHandler(response: AxiosResponse<ArrayBuffer>) {
    try {
        const decoded = CBOR.decode<{
            status: boolean
            data: string
        }>(response.data)

        // 合併所有響應日誌為一條
        cborLogger.info(`CBOR響應 [${response.config.url}]:`, {
            rawData: response.data,
            decodedData: decoded,
        })

        if (!decoded.status) {
            const errorMessage = typeof decoded.data === "string" ? decoded.data : "Unknown error"
            throw ErrorFactory.createServerError(errorMessage)
        }
        // @ts-ignore
        response.data = decoded
        return response
    } catch (error) {
        if (error instanceof CustomError) {
            if (error.message === "token") {
                tokenStore.clear()
                throw error
            }

            throw error
        }
        // 錯誤處理
        // @ts-ignore
        cborLogger.info(`CBOR解析失敗 [${response.config.url}]`, {
            data: response.data,
            error: error,
        })
        // @ts-ignore
        throw ErrorFactory.createCborError(error.message, error)
    }
}
